package com.gzs.learn.springcloud.service.impl;

import com.google.common.collect.Lists;
import com.gzs.learn.springcloud.dto.AddressDto;
import com.gzs.learn.springcloud.dto.UserDto;
import com.gzs.learn.springcloud.entity.Address;
import com.gzs.learn.springcloud.entity.User;
import com.gzs.learn.springcloud.mapstruct.AddressMS;
import com.gzs.learn.springcloud.mapstruct.UserMS;
import com.gzs.learn.springcloud.repository.AddressRepository;
import com.gzs.learn.springcloud.repository.UserRepository;
import com.gzs.learn.springcloud.service.IUserService;
import com.gzs.learn.springcloud.service.businessmsg.UserBusinessMsg;
import com.gzs.learn.springcloud.service.exception.UserSystemException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * @author zhisong.guan
 */
@Service
@RequiredArgsConstructor
@Transactional
public class UserServiceImpl implements IUserService {
    private final UserRepository userRepository;

    private final AddressRepository addressRepository;

    @Override
    public Optional<UserDto> findByUserId(Long userId) {
        Optional<User> u = userRepository.findById(userId);
        if (u.isPresent()) {
            User user = u.get();
            UserDto userDTO = UserMS.INSTANCE.toDto(user);
            userDTO.setAddresses(AddressMS.INSTANCE.toList(user.getAddresses()));
            return Optional.of(userDTO);
        }
        throw new UserSystemException(userId, "user not find");
    }

    @Override
    public Optional<User> getUser(Long userId) {
        Optional<User> u = userRepository.findById(userId);
        return u;
    }

    @Override
    public Optional<User> saveUser(User user) {
        User u = userRepository.save(user);
        return Optional.of(u);
    }

    @Override
    public Optional<Address> saveAddress(Address address) {
        Address addr = addressRepository.save(address);
        return Optional.of(addr);
    }

    @Override
    public List<Address> saveBatchAddreass(List<Address> addresses) {
        Iterable<Address> iterable = addressRepository.saveAll(addresses);
        return Lists.newArrayList(iterable);
    }

    @Override
    public Page<AddressDto> findAllByUserId(long userId, Pageable pageable) {
        Page<Address> addrs = addressRepository.findByUserId(userId, pageable);
        List<AddressDto> dtoList = Lists.newArrayList();
        for (Address address : addrs.getContent()) {
            dtoList.add(AddressMS.INSTANCE.toDto(address));
        }
        PageImpl<AddressDto> addressDtos = new PageImpl<>(dtoList, pageable, addrs.getTotalElements());
        return addressDtos;
    }

    @Override
    public List<User> findAllByIds(Set<Long> userIds) {
        List<User> userOptional = userRepository.findAllByIdIn(userIds);
        return userOptional;
    }

    @Override
    public Optional<UserDto> findByUserAndAddress(Long userId, Long addressId) {
        Optional<User> u = userRepository.findById(userId);
        if (!u.isPresent()) {
            throw new UserSystemException(userId, "user not find");
        }
        User user = u.get();
        UserDto userDTO = UserMS.INSTANCE.toDto(user);

        Address addr = user.getAddresses().stream().filter(address -> Objects.equals(address.getId(), addressId))
                .findFirst().orElse(null);
        if (addr == null) {
            String msg = String.format(UserBusinessMsg.ADDRESS_NOT_FOUND, userId, addressId);
            addr = addressRepository.findById(addressId).orElseThrow(() -> new IllegalArgumentException(msg));
        }
        userDTO.setAddresses(AddressMS.INSTANCE.toList(Lists.newArrayList(addr)));

        return Optional.of(userDTO);
    }

}
